#ifndef __KERNEL__
#define __KERNEL__
#endif /* __KERNEL__ */

#ifndef MODULE
#  define MODULE
#endif /* MODULE */

#ifdef __KERNEL__
  #include <linux/slab.h>
#define MALLOC(s, u)	(s*u < PAGE_SIZE) ? kmalloc(s*u, GFP_KERNEL) : NULL
#define FREE(p)		kfree(p)
#else /* ! __KERNEL__ */
  #include <stdlib.h>
#define MALLOC(s, u)	malloc(s*u)
#define FREE(p)		free(p)
#endif


#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <asm/semaphore.h>

#include "debug.h"
#include "buffops.h"
#include "rbuffer.h"

MODULE_AUTHOR("Carreras Rodrigo - Pellegrini Franco - Cordoba Matias");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Controlador de buffer temporal /dev/fifo");



static const int MAJOR = 254;
static const char *NAME = "fifo";

static const int BUFFER_SIZE = 100;

int init_module(void)
{
	int error = 0;
	
	mutex_read = MALLOC(1,sizeof(struct semaphore));
	mutex_write = MALLOC(1,sizeof(struct semaphore));
	mutex_buffer = MALLOC(1,sizeof(struct semaphore));
	cola_espera_read = MALLOC(1,sizeof(wait_queue_head_t));
	cola_espera_write = MALLOC(1,sizeof(wait_queue_head_t));
	
	
	init_waitqueue_head(cola_espera_write);
	init_waitqueue_head(cola_espera_read);
	
	
	sema_init(mutex_read, 1);
	sema_init(mutex_write, 1);
	sema_init(mutex_buffer, 1);
	
	
	
	error = register_chrdev(MAJOR, NAME, &buffops);
	if (error == 0) {
		
		printk(KERN_INFO "Carga, entrada del modulo\n");
		/*creo el buffer*/	
		buffer = rbuffer_create(BUFFER_SIZE);
	} else {
		dprintk("fifo: No se pudo registrar el dispositivo '%s' con"
			"major: %d.\n", NAME, MAJOR);
		error = -1;
	}
	
	return error;
}

void cleanup_module(void)
{
	int error = 0;

	error = unregister_chrdev(MAJOR, NAME);
	if (error == 0) {
		rbuffer_destroy(buffer);
		dprintk("fifo: Descarga completada satisfactoriamente.\n");
	} else {
		dprintk("fifo: No se pudo desregistrar el dispositivo '%s' con"
			" major: %d\n", NAME, MAJOR);
	}
	
	FREE(mutex_buffer);
	FREE(mutex_write);
	FREE(mutex_read);
	FREE(cola_espera_write);
	FREE(cola_espera_read);
	
	printk(KERN_INFO "salida del modulo Carga\n");
}
